<?php
/** 
 * Copyright (c) 2012, Jiehun.com.cn Inc. All Rights Reserved
 * @author Ronnie(dengxiaolong@jiehun.com.cn)
 * @date 2012-3-2
 * @version 1.0 
 * @brief 
 *  
 **/
require_once dirname(__FILE__).'/Worksheet.php';
class Excel
{
	/**
	 * @var Jiehun_Excel_Worksheet
	 */
	private $_schema;
	private $_datas;
	
	private $_version = '14.00';
	private $_create;
	private $_lastSaved;
	private $_author = 'Jiehun.Excel';
	
	private $_path;
	
	private $_count = 1;
	private $_buffer = array();
	private $_fh = null;
	
	/**
	 * 如果传入路径，excel会及时将内容写入文件，防止内存耗尽。如果没有传入路径，所有的处理都在内存进行。
	 * @param string $path
	 */
	public function __construct($path = null)
	{
		$this->_create = $this->_lastSaved = $this->formatDate();
		$this->_path = $path;
	}
	
	private function formatDate($timestamp = null)
	{
		if (null === $timestamp) {
			$timestamp = time();
		}
		return date('Y-m-d', $timestamp).'T'.date('H:i:s', $timestamp).'Z';
	}
	
	/**
	 * 将内容加入缓存
	 * @param string $content
	 */
	private function writeContent($content)
	{
		if (!$this->_path) {
			$this->_buffer[] = $content;
		} else {
			if (!$this->_fh) {
				// 只写
				$this->_fh = fopen($this->_path, 'w+');
			}
			fwrite($this->_fh, $content);
		}
	}
	
	/**
	 * 开始excel写入
	 */
	public function start()
	{
		if (!$this->_schema) {
			throw new Exception('excel.schema_not_inited');
		}
		// 将之前缓存的内容释放掉
		$this->_buffer = array();
		
		$content = $this->getHeader();
		$content .= $this->_schema->getHeader();
		$content .= $this->_schema->getSchema();
		
		$this->writeContent($content);
	}
	/**
	 * 多工作表开始excel写入
	 */
	public function multiStart()
	{
		// 将之前缓存的内容释放掉
		$this->_buffer = array();
		$content = $this->getHeader();
		$this->writeContent($content);
	}
	/**
	 * 创建一个工作表
	 */
	public function createSheet($sheet='Sheet1')
	{
		if (!$this->_schema) {
			throw new Exception('excel.schema_not_inited');
		}
		$content = $this->_schema->getHeader($sheet);
		$content .= $this->_schema->getSchema();
		
		$this->writeContent($content);
	}
	
	/**
	 * 写入数据。如果初始化时传入了文件路径，则可以分批次写入数据，便于及时释放内存
	 *
	 * @param array $rows 写入数据，格式如下：
	 * <code>
	 * 	array(
	 * 		array(
	 * 			$columnName => $value
	 * 		)
	 * 	)
	 * </code>
	 */
	public function write(array $rows)
	{
		if (!$this->_schema) {
			throw new Exception('excel.schema_not_inited');
		}
		$codes = '';//array();
		foreach($rows as $row) {
			$codes .= $this->_schema->getRow($row);
			$this->_count++;
		}
//		$this->_count += count($codes);
//		$this->writeContent(implode("\n", $codes));
		$this->writeContent($codes);
	}
	
	/**
	 * 结束excel写入
	 */
	public function end()
	{
		if (!$this->_schema) {
			throw new Exception('schema_not_inited');
		}
		
		$content = $this->_schema->getFooter();
		$content .= $this->getFooter();
		$this->writeContent($content);
		
		// 释放文件
		if ($this->_fh) {
			fclose($this->_fh);
			$this->_fh = NULL;
		}
	}
	
	/**
	 * 结束excel写入
	 */
	public function multiEnd()
	{
		if (!$this->_schema) {
			throw new Exception('schema_not_inited');
		}
		$content = $this->getFooter();
		$this->writeContent($content);
		
		// 释放文件
		if ($this->_fh) {
			fclose($this->_fh);
			$this->_fh = NULL;
		}
	}
	
	/**
	 * 工作表写入结束
	 */
	public function createSheetEnd()
	{
		if (!$this->_schema) {
			throw new Exception('excel.schema_not_inited');
		}
		$content = $this->_schema->getFooter();
		$this->writeContent($content);
	}
	
	/**
	 * 获取excel的内容
	 */
	public function getContent()
	{
		if ($this->_path) {
			return file_get_contents($this->_path);
		} else {
			return implode('', $this->_buffer);
		}		
	}
	
	/**
	 * 设置schema
	 *
	 * @param array $schemas
	 * <code>
	 * array(
	 * 	$columnName => $chineseName
	 * )
	 * </code>
	 */
	public function setSchema($schema)
	{
		if (!$this->_schema) {
			$this->_schema = new Worksheet();
		}
		$this->_schema->setSchema($schema);
	}
	
	private function getHeader()
	{
		return <<<CODE
<?xml version="1.0"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
 xmlns:o="urn:schemas-microsoft-com:office:office"
 xmlns:x="urn:schemas-microsoft-com:office:excel"
 xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
 xmlns:html="http://www.w3.org/TR/REC-html40">
 <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
  <Author>{$this->_author}</Author>
  <Created>{$this->_create}</Created>
  <LastSaved>{$this->_lastSaved}</LastSaved>
  <Version>14.00</Version>
 </DocumentProperties>
 <OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
  <AllowPNG/>
 </OfficeDocumentSettings>
 <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
  <WindowHeight>10530</WindowHeight>
  <WindowWidth>18315</WindowWidth>
  <WindowTopX>480</WindowTopX>
  <WindowTopY>90</WindowTopY>
  <ProtectStructure>False</ProtectStructure>
  <ProtectWindows>False</ProtectWindows>
 </ExcelWorkbook>
 <Styles>
  <Style ss:ID="Default" ss:Name="Normal">
   <Alignment ss:Vertical="Center"/>
   <Borders/>
   <Font ss:FontName="宋体" x:CharSet="134" ss:Size="11" ss:Color="#000000"/>
   <Interior/>
   <NumberFormat/>
   <Protection/>
  </Style>
  <Style ss:ID="s16">
   <Font ss:FontName="宋体" x:CharSet="134" ss:Size="11" ss:Bold="1"/>
   <Interior ss:Color="#FF9900" ss:Pattern="Solid"/>
  </Style>
  <Style ss:ID="s17">
   <NumberFormat ss:Format="@"/>
  </Style>
 </Styles>
CODE;
	}
	
	private function getFooter()
	{
		return <<<CODE
</Workbook>
CODE;
	}
	
	/**
	 * 释放文件句柄
	 */
	public function __destruct()
	{
		if ($this->_fh) {
			fclose($this->_fh);
		}
	}
}
